﻿using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;

namespace TheDarkKnight.MeshFactory
{

    public struct MeshShell
    {
        public Vector3[] Vertices;

        public int[] Triangles;

        public Vector3[] Normals;

        public Vector2[] UV;

        public Quaternion Rotation;

        public List<int>[] SubTriangels;

        public MeshShell(int vCapacity, int tCapcity, int subCapcity)
        {
            this.Vertices = new Vector3[vCapacity];
            this.Triangles = new int[tCapcity];
            this.Normals = new Vector3[vCapacity];
            this.UV = new Vector2[vCapacity];
            this.SubTriangels = new List<int>[subCapcity];
            this.Rotation = Quaternion.identity;
        }

        public void InitMesh(Quaternion originalRot)
        {
            this.Rotation = originalRot;
        }


        public void AddVertices(int index, Vector3 point)
        {
            this.Vertices[index] = point;
        }

        public void AddTriangles(int index, int p0, int p1, int p2)
        {
            Triangles[index] = p0;
            Triangles[index + 1] = p1;
            Triangles[index + 2] = p2;
        }

        public void AddSubTriangles(int index, List<int> triangles)
        {
            SubTriangels[index] = triangles;
        }

        public void AddNormals(int index, Vector3 point)
        {
            this.Normals[index] = point;
        }

        public void AddUV(int index, Vector2 UV)
        {
            this.UV[index] = UV;
        }

        public MeshPlus GetMesh(MeshTemplet meshTemplet, int segment)
        {
            int verticeCount = Vertices.Length;
            int triangleCount = Triangles.Length;
            Mesh mesh = new Mesh();
            mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            MeshPlus meshPlus = new MeshPlus(verticeCount, mesh, meshTemplet.Vertices, meshTemplet.Normals, meshTemplet.UV, meshTemplet.Triangels, segment);
            for (int i = 0; i < verticeCount; i++)
            {
                meshPlus.Vertices[i] = Vertices[i];
                meshPlus.Normals[i] = Normals[i];
                meshPlus.UV[i] = UV[i];
            }
            int[] triangles = new int[triangleCount];
            for (int i = 0; i < triangleCount; i++)
            {
                triangles[i] = Triangles[i];
            }
            meshPlus.MeshData.vertices = meshPlus.Vertices;
            meshPlus.MeshData.triangles = triangles;
            meshPlus.MeshData.normals = meshPlus.Normals;
            meshPlus.MeshData.uv = meshPlus.UV;
            meshPlus.MeshData.subMeshCount = (SubTriangels.Length + 1);
            for (int i = 0; i < SubTriangels.Length; i++)
            {
                meshPlus.MeshData.SetTriangles(SubTriangels[i], (i + 1));
            }
            //meshPlus.MeshData.RecalculateTangents();
            meshPlus.MeshData.RecalculateNormals();
            return meshPlus;
        }

        public MeshPlus GetMesh(HighPerformanceMeshTemplet meshTemplet, int segment)
        {
            int verticeCount = Vertices.Length;
            int triangleCount = Triangles.Length;
            Mesh mesh = new Mesh();
            mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            MeshPlus meshPlus = new MeshPlus(verticeCount, mesh, meshTemplet.Vertices, meshTemplet.Normals, meshTemplet.UV, meshTemplet.Triangels, segment);
            for (int i = 0; i < verticeCount; i++)
            {
                meshPlus.Vertices[i] = Vertices[i];
                meshPlus.Normals[i] = Normals[i];
                meshPlus.UV[i] = UV[i];
            }
            int[] triangles = new int[triangleCount];
            for (int i = 0; i < triangleCount; i++)
            {
                triangles[i] = Triangles[i];
            }
            meshPlus.MeshData.vertices = meshPlus.Vertices;
            meshPlus.MeshData.triangles = triangles;
            meshPlus.MeshData.normals = meshPlus.Normals;
            meshPlus.MeshData.uv = meshPlus.UV;
            meshPlus.MeshData.subMeshCount = (SubTriangels.Length + 1);
            for (int i = 0; i < SubTriangels.Length; i++)
            {
                meshPlus.MeshData.SetTriangles(SubTriangels[i], (i + 1));
            }
            //meshPlus.MeshData.RecalculateTangents();
            meshPlus.MeshData.RecalculateNormals();
            return meshPlus;
        }


        public void AddNativeArray(NativeArray<float3> verticesNativeArray, NativeArray<float3> normalNativeArray, NativeArray<float2> UVNativeArray, NativeArray<int> triangleNativeArray)
        {
            int verticesCount = verticesNativeArray.Length;
            int normalCount = normalNativeArray.Length;
            int UVCount = UVNativeArray.Length;
            int triangleCount = triangleNativeArray.Length;
            float3[] verticesArray = verticesNativeArray.ToArray();
            float3[] normalArray = normalNativeArray.ToArray();
            float2[] uvArray = UVNativeArray.ToArray();
            int[] triangleArray = triangleNativeArray.ToArray();
            for (int i = 0; i < verticesCount; i++)
            {
                Vertices[i] = new Vector3(verticesArray[i].x, verticesArray[i].y,verticesArray[i].z);
            }
            for (int i = 0; i < normalCount; i++)
            {
                Normals[i] = new Vector3(normalArray[i].x, normalArray[i].y, normalArray[i].z);
            }
            for (int i = 0; i < UVCount; i++)
            {
                UV[i] = new Vector2(uvArray[i].x, uvArray[i].y);
            }
            for (int i = 0; i < triangleCount; i++)
            {
                Triangles[i] = triangleArray[i];
            }
        }

    }

    public struct MeshPlus
    {

        public Mesh MeshData;

        public Vector3[] Vertices;

        public Vector3[] Normals;

        public Vector2[] UV;

        public int Segment;

        public Vector3[] Templete_Vertices;

        public Vector3[] Templete_Normals;

        public Vector2[] Templete_UV;

        public int[] Templete_Triangle;

        public MeshPlus(int vCount, Mesh mesh, Vector3[] vertices, Vector3[] normals, Vector2[] UV, int[] triangels, int segment)
        {
            this.Vertices = new Vector3[vCount];
            this.Normals = new Vector3[vCount];
            this.UV = new Vector2[vCount];
            this.Templete_Vertices = vertices;
            this.Templete_Normals = normals;
            this.Templete_UV = UV;
            this.Templete_Triangle = triangels;
            this.Segment = segment;
            this.MeshData = mesh;
        }

        public MeshPlus(int vCount, Mesh mesh, NativeArray<float3> vertices, NativeArray<float3> normals, NativeArray<float2> UV, NativeArray<int> triangels, int segment)
        {
            this.Vertices = new Vector3[vCount];
            this.Normals = new Vector3[vCount];
            this.UV = new Vector2[vCount];
            this.Templete_Vertices = new Vector3[vertices.Length];
            this.Templete_Normals = new Vector3[normals.Length];
            this.Templete_UV = new Vector2[UV.Length];
            for (int vIndex = 0; vIndex < vertices.Length; vIndex++)
            {
                Templete_Vertices[vIndex] = new float3(vertices[vIndex]);
            }
            for (int nIndex = 0; nIndex < vertices.Length; nIndex++)
            {
                Templete_Normals[nIndex] = new float3(normals[nIndex]);
            }
            for (int uvIndex = 0; uvIndex < vertices.Length; uvIndex++)
            {
                Templete_UV[uvIndex] = new float2(UV[uvIndex]);
            }
            this.Templete_Triangle = triangels.ToArray();
            this.Segment = segment;
            this.MeshData = mesh;

        }
    }

    public struct MeshTemplet
    {

        public Vector3[] Vertices;

        public int[] Triangels;

        public Vector3[] Normals;

        public Vector2[] UV;


        public MeshTemplet(Vector3[] vertices, int[] triangels, Vector3[] normals, Vector2[] uv)
        {
            this.Vertices = vertices;
            this.Triangels = triangels;
            this.Normals = normals;
            this.UV = uv;
        }

        public void DebugVertices()
        {
            for (int i = 0; i < Vertices.Length; i++)
            {
                Debug.Log("<color=red>" + Vertices[i] + "</color>");
            }
        }

        public Mesh GetMesh()
        {
            Mesh mesh = new Mesh();
            mesh.vertices = Vertices;
            mesh.triangles = Triangels;
            mesh.normals = Normals;
            mesh.uv = UV;
            return mesh;
        }

        public Mesh GetInverseMesh()
        {
            Mesh mesh = new Mesh();
            mesh.vertices = Vertices;
            mesh.triangles = InverseTriangle();
            mesh.normals = InverseNormal();
            mesh.uv = UV;
            return mesh;
        }

        private int[] InverseTriangle()
        {
            int[] inversTriangle = new int[Triangels.Length];
            for (int i = 0; i < Triangels.Length; i = i + 3)
            {
                int first = Triangels[i];
                int second = Triangels[i + 1];
                int thrid = Triangels[i + 2];
                inversTriangle[i] = first;
                inversTriangle[i + 1] = thrid;
                inversTriangle[i + 2] = second;
            }
            return inversTriangle;
        }

        private Vector3[] InverseNormal()
        {
            Vector3[] inverseNormal = new Vector3[Normals.Length];
            for (int i = 0; i < Normals.Length; i++)
            {
                inverseNormal[i] = -Normals[i];
            }
            return inverseNormal;
        }
}

    public struct HighPerformanceMeshTemplet
    {
        public NativeArray<float3> Vertices;

        public NativeArray<int> Triangels;

        public NativeArray<float3> Normals;

        public NativeArray<float2> UV;


        public HighPerformanceMeshTemplet(float3[] vertices, int[] triangels, float3[] normals, float2[] uv)
        {
            Vertices = new NativeArray<float3>(vertices, Allocator.TempJob);
            Triangels = new NativeArray<int>(triangels, Allocator.TempJob);
            Normals = new NativeArray<float3>(normals,Allocator.TempJob);
            UV = new NativeArray<float2>(uv,Allocator.TempJob);
        }

        public void DebugVertices()
        {
            for (int i = 0; i < Vertices.Length; i++)
            {
                Debug.Log("<color=red>" + Vertices[i] + "</color>");
            }
        }

        private int[] InverseTriangle()
        {
            int[] inversTriangle = new int[Triangels.Length];
            for (int i = 0; i < Triangels.Length; i = i + 3)
            {
                int first = Triangels[i];
                int second = Triangels[i + 1];
                int thrid = Triangels[i + 2];
                inversTriangle[i] = first;
                inversTriangle[i + 1] = thrid;
                inversTriangle[i + 2] = second;
            }
            return inversTriangle;
        }

        public void Dispose()
        {
            Vertices.Dispose();
            Triangels.Dispose();
            Normals.Dispose();
            UV.Dispose();
        }

    }

}

